{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QdsgF9Mxj0gr"
      },
      "source": [
        "##### Adapted from the original [*A Swift Tour*](https://docs.swift.org/swift-book/GuidedTour/GuidedTour.html) on [Swift.org](https://swift.org) with modifications. The original content was authored by Apple Inc. Licensed under the [Creative Commons Attribution 4.0 International (CC BY 4.0) License](https://creativecommons.org/licenses/by/4.0/)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pJNp_GAv9LAh"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://www.tensorflow.org/swift/tutorials/a_swift_tour\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />View on TensorFlow.org</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ja/swift/tutorials/a_swift_tour.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Run in Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ja/swift/tutorials/a_swift_tour.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />View source on GitHub</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "673eaebJdE12"
      },
      "source": [
        "# Swift ツアー\n",
        "\n",
        "慣例的に言えば、新しい言語による最初のプログラムは「Hello, world!」という言葉を画面に出力するものです。Swift では、これを単一業でやってのけることができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "iNHY9-pzdE13"
      },
      "outputs": [],
      "source": [
        "print(\"Hello, world!\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jdHsgXTYdE17"
      },
      "source": [
        "C や Objective-C でコードを記述したことのある方であれば、これは見慣れた構文でしょう。Swift では、このコード行だけで完全なプログラムが成り立っており、入力/出力または文字列の処理といった機能を得るために、ライブラリを別途インポートする必要がありません。グローバルスコープで記述されるコードはプログラムのエントリポイントとして使用されるため、`main()` 関数が不要なのです。また、ステートメントをセミコロンで終了する必要もありません。\n",
        "\n",
        "このツアーでは、さまざまなプログラミングタスクを達成する方法を示しながら、Swift でコードを書き始める上で十分な情報を提供します。わからないことに遭遇しても気にする必要はありません。このツアーで紹介される内容はすべてこの書物で詳しく説明されています。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "OihtZA6QhEZS"
      },
      "source": [
        "## 単純な値\n",
        "\n",
        "定数を作るには `let`、変数を作るには `var` を使用します。定数の値はコンパイル時に認識させる必要はありませんが、まったく一度だけ、定数に値を代入する必要があります。つまり、定数に値を一度だけ指定すれば、後はさまざまな場所で使用できるようになるということです。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "p_pjyevTdE18"
      },
      "outputs": [],
      "source": [
        "var myVariable = 42\n",
        "myVariable = 50\n",
        "let myConstant = 42"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "A7S47TpWdE1-"
      },
      "source": [
        "定数または変数の型は、それに代入する値と同じ型である必要があります。ただし、型を必ず明示的に記述しなければならないわけではありません。定数または変数を作成するときに値を指定することで、コンパイラが型を推論することができます。上記の例では、コンパイラは `myVariable` が整数であると推論しています。初期値が整数だからです。\n",
        "\n",
        "初期値に情報が不足している場合（または初期値がない場合）、変数の後にカンマ区切りで型を記述して指定します。注意: 浮動小数点数に `Float` ではなく `Double` を使用すると、精度が上がります。Swift ではデフォルトの浮動小数点数型です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "RDo7IwtmdE1_"
      },
      "outputs": [],
      "source": [
        "let implicitInteger = 70\n",
        "let implicitDouble = 70.0\n",
        "let explicitDouble: Double = 70"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "9jZ0Hccqhlil"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Create a constant with an explicit type of `Float` and a value of 4."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "N1PqnuLFXR4L"
      },
      "source": [
        "値が暗黙的に別の型に変換されることは絶対にありません。値を別の型に変換する必要がある場合は、希望する型のインスタンスを明示的に作成します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "rPuJLYsHdE2C"
      },
      "outputs": [],
      "source": [
        "let label = \"The width is \"\n",
        "let width = 94\n",
        "label + String(width)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QuQ7-JoOhNY9"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Try removing the conversion to `String` from the last line. What error do you get?"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7cwpu6_3YYKX"
      },
      "source": [
        "文字列の値は、さらに単純な方法で含めることができます。次の例のように、丸括弧に値を記述し、丸括弧の前にバックスラッシュ（`文字列の値は、さらに単純な方法で含めることができます。次の例のように、丸括弧に値を記述し、丸括弧の前にバックスラッシュ（）を記述する方法です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "j-W3HyT9ZBOF"
      },
      "outputs": [],
      "source": [
        "let apples = 3\n",
        "\"I have \\(apples) apples.\""
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kd1WEYjwZCXx"
      },
      "outputs": [],
      "source": [
        "let oranges = 5\n",
        "\"I have \\(apples + oranges) pieces of fruit.\""
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3avZRAzlguOQ"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Use `\\()` to include a floating-point calculation in a string and to include someone's name in a\n",
        "// greeting."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4T6rPJ6tWaKu"
      },
      "source": [
        "複数の行にまたがる文字列には、3 つの二重引用符（`\"\"\"`）を使用します。閉じ引用符のインデントと一致する限り、引用される各行の先頭にあるインデントは削除されます。次に例を示します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "_5RJZBV1Webt"
      },
      "outputs": [],
      "source": [
        "let quotation = \"\"\"\n",
        "    Even though there's whitespace to the left,\n",
        "    the actual lines aren't indented.\n",
        "        Except for this line.\n",
        "    Double quotes (\") can appear without being escaped.\n",
        "\n",
        "    I still have \\(apples + oranges) pieces of fruit.\n",
        "    \"\"\"\n",
        "print(quotation)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AuhL5LMzVr-T"
      },
      "source": [
        "配列とディクショナリは角括弧（`[]`）を使って作成し、要素にアクセスするには、インデックスまたはキーを各括弧に記述します。最後の要素の後に、カンマを使用できます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "BI46PGfQdE2I"
      },
      "outputs": [],
      "source": [
        "var shoppingList = [\"catfish\", \"water\", \"tulips\", \"blue paint\"]\n",
        "shoppingList[1] = \"bottle of water\"\n",
        " \n",
        "var occupations = [\n",
        "    \"Malcolm\": \"Captain\",\n",
        "    \"Kaylee\": \"Mechanic\",\n",
        "]\n",
        "occupations[\"Jayne\"] = \"Public Relations\"\n",
        "occupations"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HpaZFmGhYmW-"
      },
      "source": [
        "配列は、要素を追加するにつれて自動的に拡張します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "vVgbHKpaYpPX"
      },
      "outputs": [],
      "source": [
        "shoppingList.append(\"blue paint\")\n",
        "shoppingList"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "P_F6ODC6dE2L"
      },
      "source": [
        "空の配列またはディクショナリを作成するには、初期化構文を使用します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "pZ0hFNzXdE2M"
      },
      "outputs": [],
      "source": [
        "let emptyArray = [String]()\n",
        "let emptyDictionary = [String: Float]()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "r88SNR3mdE2Q"
      },
      "source": [
        "変数に新しい値を設定する場合や引数を関数に渡す場合など、型情報を推論できる場合は、空の配列を `[]`、空のディクショナリを `[:]` として記述できます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LrmOoh8HdE2R"
      },
      "outputs": [],
      "source": [
        "shoppingList = []\n",
        "occupations = [:]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IcyJIWOqdE2T"
      },
      "source": [
        "## 制御フロー\n",
        "\n",
        "条件文には `if` と `switch`、ループの作成には `for`-`in`、`for`、`while`、および `repeat`-`while` を使用します。条件またはループ変数を丸括弧で囲むのはオプションですが、本文を囲む波括弧は必須です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QhcmCbQydE2U"
      },
      "outputs": [],
      "source": [
        "let individualScores = [75, 43, 103, 87, 12]\n",
        "var teamScore = 0\n",
        "for score in individualScores {\n",
        "    if score > 50 {\n",
        "        teamScore += 3\n",
        "    } else {\n",
        "        teamScore += 1\n",
        "    }\n",
        "}\n",
        "teamScore"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VfEX-a-JdE2W"
      },
      "source": [
        "`if` ステートメントの条件はブール式である必要があります。`if score { ... }` といったコードはエラーであり、ゼロとの暗黙の比較ではありません。\n",
        "\n",
        "`if` と `let` を合わせて使用することで、欠落している可能性のある値を処理することができます。このような値はオプションとして表現されます。オプションの値には、値が含まれているか、値が欠落していることを示す `nil` が含まれます。値の型の後に疑問符（`?`）を記述すると、値がオプションであることを印すことができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "fCqYihmIdE2X"
      },
      "outputs": [],
      "source": [
        "var optionalString: String? = \"Hello\"\n",
        "optionalString == nil"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3GcY1w13hv82"
      },
      "outputs": [],
      "source": [
        "var optionalName: String? = \"John Appleseed\"\n",
        "var greeting = \"Hello!\"\n",
        "if let name = optionalName {\n",
        "    greeting = \"Hello, \\(name)\"\n",
        "}\n",
        "greeting"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0dJr-IC8giJL"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Change `optionalName` to `nil`. What greeting do you get?\n",
        "// Add an `else` clause that sets a different greeting if `optionalName` is `nil`."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZZWOeB3ve-jm"
      },
      "source": [
        "オプションの値が `nil` である場合、条件文は `false` となり、波括弧内のコードが省略されます。nil でない場合は、`let` の後にオプションの値が解放されて定数に代入されます。そのため解放された値をコードブロック内で利用できるようになります。\n",
        "\n",
        "オプションの値を処理するもう 1 つの方法は、`??` 演算子を使用してデフォルト値を指定する方法です。オプションの値が欠落している場合、代わりにデフォルト値が使用されます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "UqstABf4dE2b"
      },
      "outputs": [],
      "source": [
        "let nickName: String? = nil\n",
        "let fullName: String = \"John Appleseed\"\n",
        "\"Hi \\(nickName ?? fullName)\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "l_3enGZldE2d"
      },
      "source": [
        "Switch ではあらゆる種類のデータと多様な比較演算がサポートされています。整数や等価テストに制限されていません。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "AXTHsCcedE2e"
      },
      "outputs": [],
      "source": [
        "let vegetable = \"red pepper\"\n",
        "switch vegetable {\n",
        "case \"celery\":\n",
        "    print(\"Add some raisins and make ants on a log.\")\n",
        "case \"cucumber\", \"watercress\":\n",
        "    print(\"That would make a good tea sandwich.\")\n",
        "case let x where x.hasSuffix(\"pepper\"):\n",
        "    print(\"Is it a spicy \\(x)?\")\n",
        "default:\n",
        "    print(\"Everything tastes good in soup.\")\n",
        "}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "e-FK9XcGga0O"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Try removing the default case. What error do you get?"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AXaHBPiidE2g"
      },
      "source": [
        "`let` をパターンで使用して、その部分のパターンに一致した値を定数に代入できるところに注意してください。\n",
        "\n",
        "一致した switch case 内のコードを実行した後、プログラムは switch ステートメントを終了します。実行は次の case に進まないため、各 case のコードの終わりに switch を明示的に終わらせる必要がありません。\n",
        "\n",
        "ディクショナリの項目をイテレートする場合は、キー値ペアに使用する名前のペアを指定して、`for`-`in` を使用します。ディクショナリは順序不同のコレクションであるため、キーと値は任意の順序でイテレートされます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nJHpFEDPdE2h"
      },
      "outputs": [],
      "source": [
        "let interestingNumbers = [\n",
        "    \"Prime\": [2, 3, 5, 7, 11, 13],\n",
        "    \"Fibonacci\": [1, 1, 2, 3, 5, 8],\n",
        "    \"Square\": [1, 4, 9, 16, 25],\n",
        "]\n",
        "var largest = 0\n",
        "for (kind, numbers) in interestingNumbers {\n",
        "    for number in numbers {\n",
        "        if number > largest {\n",
        "            largest = number\n",
        "        }\n",
        "    }\n",
        "}\n",
        "largest"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "UKKf8zkRgWUq"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Add another variable to keep track of which kind of number was the largest, as well as what that\n",
        "// largest number was."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "or2W6kbyfuXu"
      },
      "source": [
        "条件が変わるまでコードのブロックを繰り返すには、`while` を使用します。ループの条件を最後に配置することもできるため、ループを少なくとも 1 回実行させることができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "tt54-NuJdE2m"
      },
      "outputs": [],
      "source": [
        "var n = 2\n",
        "while n < 100 {\n",
        "    n = n * 2\n",
        "}\n",
        "\n",
        "n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "adAijrWkiAGF"
      },
      "outputs": [],
      "source": [
        "var m = 2\n",
        "repeat {\n",
        "    m = m * 2\n",
        "} while m < 100\n",
        "\n",
        "m"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DqEff6OfdE2q"
      },
      "source": [
        "インデックスをループに維持することができます。`..<` を使用してインデックスの範囲を指定するか、明示的な初期化、条件、および増分を記述します。これらの 2 つのループは同じ内容を実行します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LKkJ4co_dE2r"
      },
      "outputs": [],
      "source": [
        "var total = 0\n",
        "for i in 0..<4 {\n",
        "    total += i\n",
        "}\n",
        "\n",
        "total"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HKgeaTprdE2t"
      },
      "source": [
        "`..<` を使うと、上限値を省略した範囲が作成され、`...` を使うと、両方の値を含む範囲が作成されます。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "W7H3ptGaiEcB"
      },
      "source": [
        "## 関数と閉包\n",
        "\n",
        "関数の宣言には `func` を使用します。関数の呼び出しでは、関数名の後に引数のリストを丸括弧で囲みます。`->` を使って、パラメータ名と型と、関数の戻り型を区切ります。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6u_fX5SwdE2t"
      },
      "outputs": [],
      "source": [
        "func greet(name: String, day: String) -> String {\n",
        "    return \"Hello \\(name), today is \\(day).\"\n",
        "}\n",
        "greet(name: \"Bob\", day: \"Tuesday\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sgYex6gigH87"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Remove the `day` parameter. Add a parameter to include today’s lunch special in the greeting."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Mo9D_hc0jfkF"
      },
      "source": [
        "デフォルトでは、関数はパラメータ名を引数のラベルとして使用します。カスタム引数ラベルをパラメータ名の前に記述するか、引数ラベルを使用しない場合は `_` を記述します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "8Dkx71QUjisV"
      },
      "outputs": [],
      "source": [
        "func greet(_ person: String, on day: String) -> String {\n",
        "    return \"Hello \\(person), today is \\(day).\"\n",
        "}\n",
        "greet(\"John\", on: \"Wednesday\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "71qFe0AWjd9F"
      },
      "source": [
        "関数から複数の値を返す場合など、複合値を使用するにはタプルを使います。タプルの要素は名前または数値で参照可能です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "5cDR7-TydE2w"
      },
      "outputs": [],
      "source": [
        "func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {\n",
        "    var min = scores[0]\n",
        "    var max = scores[0]\n",
        "    var sum = 0\n",
        "    \n",
        "    for score in scores {\n",
        "        if score > max {\n",
        "            max = score\n",
        "        } else if score < min {\n",
        "            min = score\n",
        "        }\n",
        "        sum += score\n",
        "    }\n",
        "    \n",
        "    return (min, max, sum)\n",
        "}\n",
        "let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])\n",
        "print(statistics.sum)\n",
        "print(statistics.2)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hHUWHaH-jwmx"
      },
      "source": [
        "関数をネストすることができます。ネストされた関数は、外側の関数で宣言された変数にアクセスできます。ネストされた関数を使用すると、長い関数や複雑な関数のコードを整理することができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "K094099VdE21"
      },
      "outputs": [],
      "source": [
        "func returnFifteen() -> Int {\n",
        "    var y = 10\n",
        "    func add() {\n",
        "        y += 5\n",
        "    }\n",
        "    add()\n",
        "    return y\n",
        "}\n",
        "returnFifteen()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "s8hfkf4HdE24"
      },
      "source": [
        "関数は第一級関数です。つまり、関数は別の関数を値として返すことができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sV33PIdsdE26"
      },
      "outputs": [],
      "source": [
        "func makeIncrementer() -> ((Int) -> Int) {\n",
        "    func addOne(number: Int) -> Int {\n",
        "        return 1 + number\n",
        "    }\n",
        "    return addOne\n",
        "}\n",
        "var increment = makeIncrementer()\n",
        "increment(7)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "J6-9e3godE29"
      },
      "source": [
        "関数は、別の関数を引数として取ることができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nOwBtGWLdE2-"
      },
      "outputs": [],
      "source": [
        "func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {\n",
        "    for item in list {\n",
        "        if condition(item) {\n",
        "            return true\n",
        "        }\n",
        "    }\n",
        "    return false\n",
        "}\n",
        "func lessThanTen(number: Int) -> Bool {\n",
        "    return number < 10\n",
        "}\n",
        "var numbers = [20, 19, 7, 12]\n",
        "hasAnyMatches(list: numbers, condition: lessThanTen)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "u9uVmoK6dE3B"
      },
      "source": [
        "関数は、実際には特殊なケースの閉包で、後で呼び出せるコードのブロックです。閉包のコードは、実行時に異なるスコープにある場合でも、それが作成されたスコープで使用できる変数と関数などにアクセスできます。この例は、ネストされた関数ですでに示されています。閉包は、名前を指定せずに、波括弧（`{}`）でコードを囲んで記述します。引数と戻り型を本文から分けるには `in` を使用します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qWTL5QMKdE3C"
      },
      "outputs": [],
      "source": [
        "numbers.map({ (number: Int) -> Int in\n",
        "    let result = 3 * number\n",
        "    return result\n",
        "})"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "aTZoZCybf2uG"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Rewrite the closure to return zero for all odd numbers."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NapuA70Qj8QF"
      },
      "source": [
        "閉包をより明確に記述するにはいくつかのオプションがあります。デリゲートのコールバックなど、閉包の型がすでに分かっている場合は、パラメータの型、戻り型、またはその両方を省略できます。単一のステートメント閉包は、暗黙的に唯一のステートメントの値を返します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "wNcmSyFodE3F"
      },
      "outputs": [],
      "source": [
        "let mappedNumbers = numbers.map({ number in 3 * number })\n",
        "print(mappedNumbers)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6MxBFQjRdE3I"
      },
      "source": [
        "パラメータは名前の代わりに数値で参照できます。これは特に非常に短い閉包で有用なアプローチです。関数の最後の引数として渡される閉包は、丸括弧の直後に出現できます。閉包が関数の唯一の引数である場合、丸括弧を完全に省略できます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6Ecv1ethdE3I"
      },
      "outputs": [],
      "source": [
        "let sortedNumbers = numbers.sorted { $0 > $1 }\n",
        "print(sortedNumbers)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BfV1d5HpdE3K"
      },
      "source": [
        "## オブジェクトとクラス\n",
        "\n",
        "クラスを作成するには、`class` の後にクラスの名前を続けます。クラスのプロパティ宣言は定数や変数の宣言と同じように記述されますが、クラスのコンテキスト内であることだけが異なります。メソッドと関数の宣言の記述も同様です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "SycTCbxadE3L"
      },
      "outputs": [],
      "source": [
        "class Shape {\n",
        "    var numberOfSides = 0\n",
        "    func simpleDescription() -> String {\n",
        "        return \"A shape with \\(numberOfSides) sides.\"\n",
        "    }\n",
        "}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "i-oNcgg4h-wm"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Add a constant property with `let`, and add another method that takes an argument."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NDuIuzgUkAEY"
      },
      "source": [
        "クラスのインスタンスは、クラス名の後に丸括弧を挿入して作成思案す。インスタンスのプロパティとメソッドにアクセスするにはドット構文を使用します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "y1_AYUbidE3O"
      },
      "outputs": [],
      "source": [
        "var shape = Shape()\n",
        "shape.numberOfSides = 7\n",
        "var shapeDescription = shape.simpleDescription()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "id0q1vIfdE3Q"
      },
      "source": [
        "このバージョンの `Shape` クラスには重要なものが欠落しています。インスタンスが作成される際にクラスをセットアップするためのイニシャライザです。イニシャライザを作成するには `init` を使います。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "lboFcMVtdE3Q"
      },
      "outputs": [],
      "source": [
        "class NamedShape {\n",
        "    var numberOfSides: Int = 0\n",
        "    var name: String\n",
        "    \n",
        "    init(name: String) {\n",
        "        self.name = name\n",
        "    }\n",
        "    \n",
        "    func simpleDescription() -> String {\n",
        "        return \"A shape with \\(numberOfSides) sides.\"\n",
        "    }\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "h06b-4fKdE3S"
      },
      "source": [
        "`name` プロパティとイニシャライザへの `name` 引数を区別するために、`self` が使用されているところに注意してください。イニシャライザへの引数は、クラスのインスタンスを作成する際の関数呼び出しのように渡されます。すべてのプロパティには、宣言内（`numberOfSides` のように）またはイニシャライザ内（`name` のように）で値を代入する必要があります。\n",
        "\n",
        "オブジェクトの割り当てを解除する前にクリーンアップを実行する場合は、`deinit` を使用してデイニシャライザを作成します。\n",
        "\n",
        "サブクラスには、クラス名の後にコロン区切りでスーパークラス名が含まれます。標準ルートクラスをサブクラス化するという要件はクラスないため、必要に応じてスーパークラスを含めるか省略してください。\n",
        "\n",
        "スーパークラスの実相をオーバーライドするサブクラスに対するメソッドは `override` でマークされます。誤って `override` を使用せずにメソッドをオーバーライドしている部分は、コンパイラよってにエラーとして検出されます。コンパイラは、スーパークラスのどのメソッドもオーバーライドしない `override` 付きのメソッドも検出します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VHT1Lpz8dE3S"
      },
      "outputs": [],
      "source": [
        "class Square: NamedShape {\n",
        "    var sideLength: Double\n",
        "    \n",
        "    init(sideLength: Double, name: String) {\n",
        "        self.sideLength = sideLength\n",
        "        super.init(name: name)\n",
        "        numberOfSides = 4\n",
        "    }\n",
        "    \n",
        "    func area() -> Double {\n",
        "        return sideLength * sideLength\n",
        "    }\n",
        "    \n",
        "    override func simpleDescription() -> String {\n",
        "        return \"A square with sides of length \\(sideLength).\"\n",
        "    }\n",
        "}\n",
        "let test = Square(sideLength: 5.2, name: \"my test square\")\n",
        "test.area()\n",
        "test.simpleDescription()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "SIoEXii5iDA3"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// - Make another subclass of `NamedShape` called `Circle` that takes a radius and a name as\n",
        "//   arguments to its initializer.\n",
        "// - Implement an `area()` and a `simpleDescription()` method on the `Circle` class."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-jWyfN7KkDqR"
      },
      "source": [
        "保存されている単純なプロパティのほかに、プロパティには getter と setter もあります。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QaqZC56MdE3V"
      },
      "outputs": [],
      "source": [
        "class EquilateralTriangle: NamedShape {\n",
        "    var sideLength: Double = 0.0\n",
        "    \n",
        "    init(sideLength: Double, name: String) {\n",
        "        self.sideLength = sideLength\n",
        "        super.init(name: name)\n",
        "        numberOfSides = 3\n",
        "    }\n",
        "    \n",
        "    var perimeter: Double {\n",
        "        get {\n",
        "            return 3.0 * sideLength\n",
        "        }\n",
        "        set {\n",
        "            sideLength = newValue / 3.0\n",
        "        }\n",
        "    }\n",
        "    \n",
        "    override func simpleDescription() -> String {\n",
        "        return \"An equilateral triangle with sides of length \\(sideLength).\"\n",
        "    }\n",
        "}\n",
        "var triangle = EquilateralTriangle(sideLength: 3.1, name: \"a triangle\")\n",
        "print(triangle.perimeter)\n",
        "triangle.perimeter = 9.9\n",
        "print(triangle.sideLength)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "CK3s64WhdE3W"
      },
      "source": [
        "`perimeter` の setter では、新しい値に `newValue` という暗黙の名前がつけられます。明示的な名前は `set` の後に丸括弧で囲んで指定できます。\n",
        "\n",
        "`EquilateralTriangle` クラスのイニシャライザには次の 3 つのステップがあります。\n",
        "\n",
        "1. サブクラスが宣言するプロパティの値を設定する。\n",
        "\n",
        "2. スーパークラスのイニシャライザを呼び出す。\n",
        "\n",
        "3. スーパークラスが定義したプロパティの値を変更する。メソッド、getter、または setter を使用するその他のセットアップ作業は、この時点で追加できます。\n",
        "\n",
        "プロパティを計算する必要がなくても、新しい値の設定前と後に実行されるコードを指定する必要がある場合は、`willSet` と `didSet` を使用します。指定したコードはイニシャライザの外部で値が変更されるたびに実行されます。たとえば、次のコードのクラスは、triangle（三角形）の辺の長さが四角形の辺の長さと常に同じであることを保証しています。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VSPCTz5mdE3a"
      },
      "outputs": [],
      "source": [
        "class TriangleAndSquare {\n",
        "    var triangle: EquilateralTriangle {\n",
        "        willSet {\n",
        "            square.sideLength = newValue.sideLength\n",
        "        }\n",
        "    }\n",
        "    var square: Square {\n",
        "        willSet {\n",
        "            triangle.sideLength = newValue.sideLength\n",
        "        }\n",
        "    }\n",
        "    init(size: Double, name: String) {\n",
        "        square = Square(sideLength: size, name: name)\n",
        "        triangle = EquilateralTriangle(sideLength: size, name: name)\n",
        "    }\n",
        "}\n",
        "var triangleAndSquare = TriangleAndSquare(size: 10, name: \"another test shape\")\n",
        "print(triangleAndSquare.square.sideLength)\n",
        "print(triangleAndSquare.triangle.sideLength)\n",
        "triangleAndSquare.square = Square(sideLength: 50, name: \"larger square\")\n",
        "print(triangleAndSquare.triangle.sideLength)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ygWAN55xdE3b"
      },
      "source": [
        "オプションの値を使用する際、メソッド、プロパティ、およびサブスクリプティングなどの演算の前に `?` を挿入します。`?` の前の値が `nil` である場合、`?` 以降のすべてのコードは無視され、式全体の値が `nil` となります。そうでない場合は、オプションの値が解放され、`?` 以降のコードがその値に作用します。いずれの場合でも、式全体の値はオプションの値です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "pmXsLt_gdE3c"
      },
      "outputs": [],
      "source": [
        "let optionalSquare: Square? = Square(sideLength: 2.5, name: \"optional square\")\n",
        "optionalSquare?.sideLength"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0yaZFHMRdE3d"
      },
      "source": [
        "## 列挙と構造\n",
        "\n",
        "列挙を作成するには `enum` を使用します。クラスやその他すべての名前付きの型と同様に、列挙には、それに関連付けられたメソッドがあります。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Btg1_6rXdE3e"
      },
      "outputs": [],
      "source": [
        "enum Rank: Int {\n",
        "    case ace = 1\n",
        "    case two, three, four, five, six, seven, eight, nine, ten\n",
        "    case jack, queen, king\n",
        "\n",
        "    func simpleDescription() -> String {\n",
        "        switch self {\n",
        "        case .ace:\n",
        "            return \"ace\"\n",
        "        case .jack:\n",
        "            return \"jack\"\n",
        "        case .queen:\n",
        "            return \"queen\"\n",
        "        case .king:\n",
        "            return \"king\"\n",
        "        default:\n",
        "            return String(self.rawValue)\n",
        "        }\n",
        "    }\n",
        "}\n",
        "let ace = Rank.ace\n",
        "print(ace)\n",
        "let aceRawValue = ace.rawValue\n",
        "print(aceRawValue)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "34Ba8HGwin9n"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Write a function that compares two `Rank` values by comparing their raw values."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0R1w6q3KkIH1"
      },
      "source": [
        "デフォルトでは、Swift は生の値を 0 から代入し、毎回 1 を増分しますが、値を明示的に指定することで、この動作を変更することができます。上記の例では、Ace に生の値 `1` が明示的に指定されており、残りの生の値が順に代入されています。生の列挙型として、文字列や浮動小数点数を使用することもできます。列挙ケースの生の値には `rawValue` プロパティを使ってアクセスします。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zgtd86KUp5qa"
      },
      "source": [
        "生の値から列挙のインスタンスを作成するには、`init?(rawValue:)` イニシャライザを使用します。個のイニシャライザは生の値に一致している列挙ケースか、一致する `Rank` がない場合は `nil` を返します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "BjzxKC67dE3h"
      },
      "outputs": [],
      "source": [
        "if let convertedRank = Rank(rawValue: 3) {\n",
        "    let threeDescription = convertedRank.simpleDescription()\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "aViNXJOWdE3k"
      },
      "source": [
        "列挙のケースの値は実際の値であり、単に別の手法で生の値を記述しているだけではありません。そのため、意味のある生の値が存在しない場合でも、意味のある値を指定する必要はありません。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "i9fKzaQzdE3k"
      },
      "outputs": [],
      "source": [
        "enum Suit {\n",
        "    case spades, hearts, diamonds, clubs\n",
        "\n",
        "    func simpleDescription() -> String {\n",
        "        switch self {\n",
        "        case .spades:\n",
        "            return \"spades\"\n",
        "        case .hearts:\n",
        "            return \"hearts\"\n",
        "        case .diamonds:\n",
        "            return \"diamonds\"\n",
        "        case .clubs:\n",
        "            return \"clubs\"\n",
        "        }\n",
        "    }\n",
        "}\n",
        "let hearts = Suit.hearts\n",
        "let heartsDescription = hearts.simpleDescription()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "H-38gQ27isHk"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Add a `color()` method to `Suit` that returns \"black\" for spades and clubs, and returns \"red\" for\n",
        "// hearts and diamonds."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "H1B0m_prdE3m"
      },
      "source": [
        "上記のコードでは、列挙の `Hearts` ケースが 2 通りで参照されているところに注意してください。`hearts` 定数に値を代入する際、定数に明示的な型が指定されていないため、列挙ケースの `Suit.Hearts` は完全名で参照されています。一方、`self` の値は suit であることがすでに分かっているため、switch 内では、列挙ケースは省略形の `.Hearts` として参照されています。値の型がすでに認識されている場合は、いつでも省略形を使用できます。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fCDHUHBHdE3o"
      },
      "source": [
        "列挙に生の値が含まれる場合、その値は宣言の一部として捉えられます。つまり、特定の列挙ケースのすべてのインスタンスには必ず同じ生の値が含まれることになります。列挙ケースの別の方法として、ケースに関連した値を含めることが挙げられます。この値はインスタンスを作成する際に指定されるため、列挙ケースのインスタンスごとに異なります。列挙ケースインスタンスの格納プロパティのように振る舞う値として関連値を考えるとよいでしょう。\n",
        "\n",
        "たとえば、サーバーに日の出と日没の時刻をリクエストするケースを考察してみましょう。このサーバーはリクエストされた情報で応答するか、エラーの説明を返します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "v7CDdsdydE3o"
      },
      "outputs": [],
      "source": [
        "enum ServerResponse {\n",
        "    case result(String, String)\n",
        "    case failure(String)\n",
        "}\n",
        "\n",
        "let success = ServerResponse.result(\"6:00 am\", \"8:09 pm\")\n",
        "let failure = ServerResponse.failure(\"Out of cheese.\")\n",
        "\n",
        "switch success {\n",
        "case let .result(sunrise, sunset):\n",
        "    print(\"Sunrise is at \\(sunrise) and sunset is at \\(sunset).\")\n",
        "case let .failure(message):\n",
        "    print(\"Failure...  \\(message)\")\n",
        "}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6KxPZi0ii4Jj"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Add a third case to `ServerResponse` and to the switch."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BCjUxgx0iKDh"
      },
      "source": [
        "switch ケースに対して値を一致させる過程の一環として、`ServerResponse` の値から日の出と日没の時刻が抽出されているところに注意してください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FonxodFmpPXv"
      },
      "source": [
        "構造を作成するには `struct` を使用します。構造は、メソッドやイニシャライザなど、クラスと同じ多くの動作をサポートしています。構造とクラスの最も重要な違いの 1 つは、構造がコード内で渡される際は必ず構造が複製されますが、クラスは参照によって渡されることです。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "tsTnhpukpTF1"
      },
      "outputs": [],
      "source": [
        "struct Card {\n",
        "    var rank: Rank\n",
        "    var suit: Suit\n",
        "    func simpleDescription() -> String {\n",
        "        return \"The \\(rank.simpleDescription()) of \\(suit.simpleDescription())\"\n",
        "    }\n",
        "}\n",
        "let threeOfSpades = Card(rank: .three, suit: .spades)\n",
        "let threeOfSpadesDescription = threeOfSpades.simpleDescription()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "FM1U4SqwpUp6"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Write a function that returns an array containing a full deck of cards, with one card of each\n",
        "// combination of rank and suit."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jUBjQqUhdE3p"
      },
      "source": [
        "## プロトコルと拡張機能\n",
        "\n",
        "プロトコルを宣言するには `protocol` を使用します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "vVEIH7WhdE3q"
      },
      "outputs": [],
      "source": [
        "protocol ExampleProtocol {\n",
        "    var simpleDescription: String { get }\n",
        "    mutating func adjust()\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GSV2yv6SdE3r"
      },
      "source": [
        "クラス、列挙、構造はすべてプロトコルを採用できます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Lgf8If-0dE3r"
      },
      "outputs": [],
      "source": [
        "class SimpleClass: ExampleProtocol {\n",
        "    var simpleDescription: String = \"A very simple class.\"\n",
        "    var anotherProperty: Int = 69105\n",
        "    func adjust() {\n",
        "        simpleDescription += \"  Now 100% adjusted.\"\n",
        "    }\n",
        "}\n",
        "var a = SimpleClass()\n",
        "a.adjust()\n",
        "let aDescription = a.simpleDescription\n",
        " \n",
        "struct SimpleStructure: ExampleProtocol {\n",
        "    var simpleDescription: String = \"A simple structure\"\n",
        "    mutating func adjust() {\n",
        "        simpleDescription += \" (adjusted)\"\n",
        "    }\n",
        "}\n",
        "var b = SimpleStructure()\n",
        "b.adjust()\n",
        "b.simpleDescription"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "OvDuEwsYi-ZN"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Add another requirement to `ExampleProtocol`.\n",
        "// What changes do you need to make to `SimpleClass` and `SimpleStructure` so that they still\n",
        "// conform to the protocol?"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Is_xfbNXdE3t"
      },
      "source": [
        "構造を変更するメソッドをマーキングする際に、`SimpleStructure` の宣言内に `mutating` キーワードが使用されているところに注意してください。クラスのメソッドはクラスを必ず変更できるため、`SimpleClass` の宣言には、メソッドが mutating としてマーキングされている必要はありません。\n",
        "\n",
        "新しいメソッドや計算されたプロパティなど、既存の型に機能を追加するには `extension` を使用します。extension を使用すると、別の場所で宣言されている型に合った、またはライブラリやフレームワークからインポートした型であってもそれに合ったプロトコルを追加することができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "w5Hde1HwdE3u"
      },
      "outputs": [],
      "source": [
        "extension Int: ExampleProtocol {\n",
        "    public var simpleDescription: String {\n",
        "        return \"The number \\(self)\"\n",
        "    }\n",
        "    public mutating func adjust() {\n",
        "        self += 42\n",
        "    }\n",
        "}\n",
        "7.simpleDescription"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "fdY5CdWjjCRI"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Write an extension for the `Double` type that adds an `absoluteValue` property."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EoOPuRjZntCx"
      },
      "source": [
        "型が異なっていても 1 つのプロトコルに準拠しているオブジェクトのコレクションを作成するためなどに、ほかの名前付きの型と同様にプロトコル名を使用できます。型がプロトコル型の値を扱う場合は、プロトコルに定義されていないメソッドを利用することはできません。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "OghTVgiRnvgA"
      },
      "outputs": [],
      "source": [
        "let protocolValue: ExampleProtocol = a\n",
        "protocolValue.simpleDescription"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Xad6Z5Nrn34O"
      },
      "outputs": [],
      "source": [
        "// Uncomment to see the error.\n",
        "// protocolValue.anotherProperty"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "92wBiymPn3HE"
      },
      "source": [
        "変数 `protocolValue` にはランタイム型 `SimpleClass` がありますが、コンパイラは指定された型の `ExampleProtocol` として処理します。つまり、クラスがプロトコル準拠とは別に実装するメソッドやプロパティに偶発的にアクセスすることはできません。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6Z9Y-fWGjxsn"
      },
      "source": [
        "## エラー処理\n",
        "\n",
        "エラーの表現には、`Error` プロトコルを採用するすべての型を使うことができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PiENY4W2kA2t"
      },
      "outputs": [],
      "source": [
        "enum PrinterError: Error {\n",
        "    case outOfPaper\n",
        "    case noToner\n",
        "    case onFire\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Tu7q13kSkCad"
      },
      "source": [
        "エラーをスローするには `throw`、エラーをスローできる関数をマークするには `throws` を使用します。関数内でエラーをスローする場合、関数は即時に返され、その関数を呼び出したコードによってエラーが処理されます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "rY7yWs_nkFbM"
      },
      "outputs": [],
      "source": [
        "func send(job: Int, toPrinter printerName: String) throws -> String {\n",
        "    if printerName == \"Never Has Toner\" {\n",
        "        throw PrinterError.noToner\n",
        "    }\n",
        "    return \"Job sent\"\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uVh7tkr-kPKV"
      },
      "source": [
        "エラー処理にはさまざまな方法がありますが、1 つは `do-catch` を使用する方法です。`do` ブロック内で、エラーをスローできるコードの前に try を使ってマーキングします。`catch` 内のエラーには、名前を指定しない限り自動的に `error` という名前が指定されます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "YejV2PLLkIPA"
      },
      "outputs": [],
      "source": [
        "do {\n",
        "    let printerResponse = try send(job: 1040, toPrinter: \"Bi Sheng\")\n",
        "    print(printerResponse)\n",
        "} catch {\n",
        "    print(error)\n",
        "}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "UJBF1XzdkWjL"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Change the printer name to `\"Never Has Toner\"`, so that the `send(job:toPrinter:)` function\n",
        "// throws an error."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "occBM2Cekddc"
      },
      "source": [
        "特定のエラーを処理する `catch` ブロックを複数指定することができます。switch 内の `case` と同様に、`catch` の後にパターンを記述します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "eUhzxcUEkjV-"
      },
      "outputs": [],
      "source": [
        "do {\n",
        "    let printerResponse = try send(job: 1440, toPrinter: \"Gutenberg\")\n",
        "    print(printerResponse)\n",
        "} catch PrinterError.onFire {\n",
        "    print(\"I'll just put this over here, with the rest of the fire.\")\n",
        "} catch let printerError as PrinterError {\n",
        "    print(\"Printer error: \\(printerError).\")\n",
        "} catch {\n",
        "    print(error)\n",
        "}"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "-qpkCM8NnXie"
      },
      "outputs": [],
      "source": [
        "// Experiment:\n",
        "// Add code to throw an error inside the `do` block.\n",
        "// What kind of error do you need to throw so that the error is handled by the first `catch` block?\n",
        "// What about the second and third blocks?"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JOwTXVWbnAup"
      },
      "source": [
        "エラー処理のもう 1 つの方法は、`try?` を使って結果をオプションに変換する方法です。関数がエラーをスローすると、特定のエラーを破棄し、結果を `nil` にしますが、そうでない場合は、結果は関数が返す値を含むオプションとなります。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2ifK6Lyom-9Q"
      },
      "outputs": [],
      "source": [
        "let printerSuccess = try? send(job: 1884, toPrinter: \"Mergenthaler\")\n",
        "let printerFailure = try? send(job: 1885, toPrinter: \"Never Has Toner\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SmSiz49knFZY"
      },
      "source": [
        "関数内のすべてのコードが実行された後に実行されるコードのブロックを記述するには、関数が返される直前に `defer` を使用します。コードは、関数がエラーをスローするかに関係なく実行されます。`defer` を使用すると、セットアップコードとクリーンアップコードを別々のタイミングで実行する必要がある場合でも、隣り合わせに記述することができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "tMdhw71anJbP"
      },
      "outputs": [],
      "source": [
        "var fridgeIsOpen = false\n",
        "let fridgeContent = [\"milk\", \"eggs\", \"leftovers\"]\n",
        "\n",
        "func fridgeContains(_ food: String) -> Bool {\n",
        "    fridgeIsOpen = true\n",
        "    defer {\n",
        "        fridgeIsOpen = false\n",
        "    }\n",
        "\n",
        "    let result = fridgeContent.contains(food)\n",
        "    return result\n",
        "}\n",
        "fridgeContains(\"banana\")\n",
        "fridgeIsOpen"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "g0wCWqNMiOv-"
      },
      "source": [
        "## ジェネリック\n",
        "\n",
        "ジェネリック関数または汎用型を作成するには、山括弧内に名前を記述します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sMyq1uQsdE3y"
      },
      "outputs": [],
      "source": [
        "func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {\n",
        "    var result = [Item]()\n",
        "    for _ in 0..<numberOfTimes {\n",
        "        result.append(item)\n",
        "    }\n",
        "    return result\n",
        "}\n",
        "makeArray(repeating: \"knock\", numberOfTimes: 4)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "If8pw1_7dE3z"
      },
      "source": [
        "関数やメソッド、さらにはクラス、列挙、および構造の汎用形式を作成できます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PrhmI6iNdE30"
      },
      "outputs": [],
      "source": [
        "// Reimplement the Swift standard library's optional type\n",
        "enum OptionalValue<Wrapped> {\n",
        "    case none\n",
        "    case some(Wrapped)\n",
        "}\n",
        "var possibleInteger: OptionalValue<Int> = .none\n",
        "possibleInteger = .some(100)\n",
        "print(possibleInteger)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NXhFj_GCdE31"
      },
      "source": [
        "型名の後に `where` を使用すると、要件のリストを指定することができます。たとえば、型にプロトコルを実装する必要がある場合、2 つの型を同一にする必要がある場合、またはクラスに特定のサブクラスを指定する場合などが挙げられます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "EkXn4tmhdE32"
      },
      "outputs": [],
      "source": [
        "func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool\n",
        "    where T.Element: Equatable, T.Element == U.Element\n",
        "{\n",
        "    for lhsItem in lhs {\n",
        "        for rhsItem in rhs {\n",
        "            if lhsItem == rhsItem {\n",
        "                return true\n",
        "            }\n",
        "        }\n",
        "    }\n",
        "    return false\n",
        "}\n",
        "anyCommonElements([1, 2, 3], [3])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6cZJ4EiYq33D"
      },
      "source": [
        "`<T: Equatable>` は、`<T> ... where T: Equatable` と記述することと同じです。"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "a_swift_tour.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Swift",
      "name": "swift"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
